//
//  ___FILENAME___
//  ___PACKAGENAME___
//
//  Created by ___FULLUSERNAME___ on ___DATE___.
//  Copyright (c) ___YEAR___ ___ORGANIZATIONNAME___. All rights reserved.
//

#import "GLViewController.h"
#import "ConstantsAndMacros.h"
#import "OpenGLCommon.h"

@implementation GLViewController

- (void)loadView
{
    GLView *viewGL = [[GLView alloc] init];
    viewGL.delegate = self;
    self.view = viewGL;
    [viewGL release];
	
	[viewGL startAnimation];
}

- (void)caculateNormals {
	
	static const Vertex3D vertices[]= {
        {0, -0.525731, 0.850651},             // vertices[0]
        {0.850651, 0, 0.525731},              // vertices[1]
        {0.850651, 0, -0.525731},             // vertices[2]
        {-0.850651, 0, -0.525731},            // vertices[3]
        {-0.850651, 0, 0.525731},             // vertices[4]
        {-0.525731, 0.850651, 0},             // vertices[5]
        {0.525731, 0.850651, 0},              // vertices[6]
        {0.525731, -0.850651, 0},             // vertices[7]
        {-0.525731, -0.850651, 0},            // vertices[8]
        {0, -0.525731, -0.850651},            // vertices[9]
        {0, 0.525731, -0.850651},             // vertices[10]
        {0, 0.525731, 0.850651}               // vertices[11]
    };
	
    static const GLubyte icosahedronFaces[] = {
        1, 2, 6,
        1, 7, 2,
        3, 4, 5,
        4, 3, 8,
        6, 5, 11,
        5, 6, 10,
        9, 10, 2,
        10, 9, 3,
        7, 8, 9,
        8, 7, 0,
        11, 0, 1,
        0, 11, 4,
        6, 2, 10,
        1, 6, 11,
        3, 5, 10,
        5, 4, 11,
        2, 7, 9,
        7, 1, 0,
        3, 9, 8,
        4, 8, 0,
    };
	
    Vector3D *surfaceNormals = calloc(20, sizeof(Vector3D));
	
	
    for (int i = 0; i < 20; i++)
    {
        Vertex3D vertex1 = vertices[icosahedronFaces[(i*3)]];
        Vertex3D vertex2 = vertices[icosahedronFaces[(i*3)+1]];
        Vertex3D vertex3 = vertices[icosahedronFaces[(i*3)+2]];
		
        Triangle3D triangle = Triangle3DMake(vertex1, vertex2, vertex3);
		
        Vector3D surfaceNormal = Triangle3DCalculateSurfaceNormal(triangle);
        Vector3DNormalize(&surfaceNormal);
        surfaceNormals[i] = surfaceNormal;
    }
	
    Vertex3D *normals = calloc(12, sizeof(Vertex3D));
	
	NSMutableString * result = [NSMutableString stringWithString:@""];
    [result appendString:@"static const Vector3D normals[] = {\n"];
	
    for (int i = 0; i < 12; i++) //12 个顶点
    {
        int faceCount = 0; //共用面
        for (int j = 0; j < 20; j++) //20 个面
        {
            BOOL contains = NO;
            for (int k = 0; k < 3; k++)
            {
                if (icosahedronFaces[(j * 3) + k] == i)
                    contains = YES;
            }
            if (contains)
            {
                faceCount++;
                normals[i] = Vector3DAdd(normals[i], surfaceNormals[j]);
            }
        }
		
        normals[i].x /= (GLfloat)faceCount;
        normals[i].y /= (GLfloat)faceCount;
        normals[i].z /= (GLfloat)faceCount;
        [result appendFormat:@"\t{%f, %f, %f},\n", normals[i].x, normals[i].y, normals[i].z];
    }
    [result appendString:@"};\n"];
	
    NSLog(@"%@",result);
}

- (void)drawCubes {
	static GLfloat rot = 0.0;
	
	static const Vertex3D vertices[]= {
        {0, -0.525731, 0.850651},             // vertices[0]
        {0.850651, 0, 0.525731},              // vertices[1]
        {0.850651, 0, -0.525731},             // vertices[2]
        {-0.850651, 0, -0.525731},            // vertices[3]
        {-0.850651, 0, 0.525731},             // vertices[4]
        {-0.525731, 0.850651, 0},             // vertices[5]
        {0.525731, 0.850651, 0},              // vertices[6]
        {0.525731, -0.850651, 0},             // vertices[7]
        {-0.525731, -0.850651, 0},            // vertices[8]
        {0, -0.525731, -0.850651},            // vertices[9]
        {0, 0.525731, -0.850651},             // vertices[10]
        {0, 0.525731, 0.850651}               // vertices[11]
    };
	
	static const Color3D colors[] = {
		{1.0, 0.0, 0.0, 1.0},
		{1.0, 0.5, 0.0, 1.0},
		{1.0, 1.0, 0.0, 1.0},
		{0.5, 1.0, 0.0, 1.0},
		{0.0, 1.0, 0.0, 1.0},
		{0.0, 1.0, 0.5, 1.0},
		{0.0, 1.0, 1.0, 1.0},
		{0.0, 0.5, 1.0, 1.0},
		{0.0, 0.0, 1.0, 1.0},
		{0.5, 0.0, 1.0, 1.0},
		{1.0, 0.0, 1.0, 1.0},
		{1.0, 0.0, 0.5, 1.0}
    };
	
	static const GLubyte icosahedronFaces[] = {
        1, 2, 6, //第一个点:{0.850651, 0, 0.525731} 第二个点:{0.850651, 0, -0.525731} 第6个点:{0.525731, 0.850651, 0} 构成的三角形
        1, 7, 2,
        3, 4, 5,
        4, 3, 8,
        6, 5, 11,
        5, 6, 10,
        9, 10, 2,
        10, 9, 3,
        7, 8, 9,
        8, 7, 0,
        11, 0, 1,
        0, 11, 4,
        6, 2, 10,
        1, 6, 11,
        3, 5, 10,
        5, 4, 11,
        2, 7, 9,
        7, 1, 0,
        3, 9, 8,
        4, 8, 0,
    };
	
	static const Vector3D normals[] = { //顶点法线向量
        {0.000000, -0.417775, 0.675974},
        {0.675973, 0.000000, 0.417775},
        {0.675973, -0.000000, -0.417775},
        {-0.675973, 0.000000, -0.417775},
        {-0.675973, -0.000000, 0.417775},
        {-0.417775, 0.675974, 0.000000},
        {0.417775, 0.675973, -0.000000},
        {0.417775, -0.675974, 0.000000},
        {-0.417775, -0.675974, 0.000000},
        {0.000000, -0.417775, -0.675973},
        {0.000000, 0.417775, -0.675974},
        {0.000000, 0.417775, 0.675973},
    };
	
	glLoadIdentity();
    glClearColor(0.7, 0.7, 0.7, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);
	glEnableClientState(GL_NORMAL_ARRAY);
	glEnable(GL_COLOR_MATERIAL);
	
    glVertexPointer(3, GL_FLOAT, 0, vertices);
    glColorPointer(4, GL_FLOAT, 0, colors);
	glNormalPointer(GL_FLOAT, 0, normals);
	
	glTranslatef(0.0f,0.0,-3.0f);
	glRotatef(rot, 1.0, 1.0, 1.0);
	glDrawElements(GL_TRIANGLES, 60, GL_UNSIGNED_BYTE, icosahedronFaces);
	
    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_COLOR_ARRAY);
	glDisableClientState(GL_NORMAL_ARRAY);
	glDisable(GL_COLOR_MATERIAL);
	
    static NSTimeInterval lastDrawTime;
    if (lastDrawTime)
    {
        NSTimeInterval timeSinceLastDraw = [NSDate timeIntervalSinceReferenceDate] - lastDrawTime;
        rot+=50 * timeSinceLastDraw;
    }
	
    lastDrawTime = [NSDate timeIntervalSinceReferenceDate];
}


#pragma mark - GLViewDelegate

- (void)drawView:(UIView *)theView
{
	[self drawCubes];
}

#pragma mark - Setup View

-(void)setupView:(GLView*)view
{
	const GLfloat zNear = 0.01, zFar = 1000.0, fieldOfView = 45.0;
    GLfloat size;
    glEnable(GL_DEPTH_TEST);
    glMatrixMode(GL_PROJECTION);
    size = zNear * tanf(DEGREES_TO_RADIANS(fieldOfView) / 2.0);
    CGRect rect = view.bounds;
    glFrustumf(-size, size, -size / (rect.size.width / rect.size.height), size /
               (rect.size.width / rect.size.height), zNear, zFar);
    glViewport(0, 0, rect.size.width, rect.size.height);
    glMatrixMode(GL_MODELVIEW);
	
    // Enable lighting
    glEnable(GL_LIGHTING);
	
    // Turn the first light on
    glEnable(GL_LIGHT0);
	
    // Define the ambient component of the first light
    static const Color3D light0Ambient[] = {{0.05, 0.05, 0.05, 1.0}};
    glLightfv(GL_LIGHT0, GL_AMBIENT, (const GLfloat *)light0Ambient);
	
    // Define the diffuse component of the first light
    static const Color3D light0Diffuse[] = {{0.4, 0.4, 0.4, 1.0}};
    glLightfv(GL_LIGHT0, GL_DIFFUSE, (const GLfloat *)light0Diffuse);
	
    // Define the specular component and shininess of the first light
    static const Color3D light0Specular[] = {{0.7, 0.7, 0.7, 1.0}};
    glLightfv(GL_LIGHT0, GL_SPECULAR, (const GLfloat *)light0Specular);
    glLightf(GL_LIGHT0, GL_SHININESS, 0.4);
	
    // Define the position of the first light
	// const GLfloat light0Position[] = {10.0, 10.0, 10.0};
    static const Vertex3D light0Position[] = {{10.0, 10.0, 10.0}};
    glLightfv(GL_LIGHT0, GL_POSITION, (const GLfloat *)light0Position);
	
    // Calculate light vector so it points at the object
    static const Vertex3D objectPoint[] = {{0.0, 0.0, -3.0}};
    const Vertex3D lightVector = Vector3DMakeWithStartAndEndPoints(light0Position[0], objectPoint[0]);
    glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, (GLfloat *)&lightVector);
	
    // Define a cutoff angle. This defines a 50° field of vision, since the cutoff
    // is number of degrees to each side of an imaginary line drawn from the light's
    // position along the vector supplied in GL_SPOT_DIRECTION above
    glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 25.0);
	
    glLoadIdentity();
	
	//[self caculateNormals];
}

@end
